home *** CD-ROM | disk | FTP | other *** search
- ; Not copyrighted by Paul Kienitz, 20 Jun 94.
- ;
- ; Assembly language version of inflate_codes(), for Amiga. Prototype:
- ;
- ; int flate_codes(struct huft *tl, struct huft *td, int bl, int bd,
- ; unsigned char *slide);
- ;
- ; It is called by defining inflate_codes(tl, td, bl, bd) as
- ; flate_codes(tl, td, bl, bd, slide).
- ;
- ; Define the symbol FUNZIP if this is for fUnZip. Define CRYPT if this is
- ; for fUnZip with decryption enabled. Define AZTEC to use the Aztec C
- ; buffered input macro instead of the library getc() with FUNZIP.
- ;
- ; => int MUST BE 16 BITS!!! <= => WSIZE MUST BE 32K! <=
- ;
- ; struct huft is defined as follows:
- ;
- ; struct huft {
- ; uch e; /* number of extra bits or operation */
- ; uch b; /* number of bits in this code or subcode */
- ; union {
- ; ush n; /* literal, length base, or distance base */
- ; struct huft *t; /* pointer to next level of table */
- ; } v;
- ; }; /* sizeof(struct huft) == 6 */
- ;
- ; so here we define the offsets of the various members of this struct:
-
- h_e equ 0
- h_b equ 1
- h_n equ 2
- h_t equ 2
- SIZEOF_HUFT equ 6
-
- ; There are several global variables we need to access. Their definitions:
- ;
- ; unsigned long bb;
- ; unsigned int bk, wp;
- ; unsigned short mask[17];
- ; FILE *in;
- ; int encrypted; /* FUNZIP CRYPT only */
- ;
- ; int incnt, mem_mode; /* non-FUNZIP only */
- ; long csize; /* non-FUNZIP only */
- ; unsigned long outcnt; /* non-FUNZIP only */
- ; unsigned char *inptr; /* non-FUNZIP only */
- ;
- ; bb is the global buffer that holds bits from the huffman code stream, which
- ; we cache in the register variable b. bk is the number of valid bits in it,
- ; which we cache in k. The macros NEEDBITS(n) and DUMPBITS(n) have side effects
- ; on b and k.
-
- xref _bb
- xref _bk
- xref _mask
- xref _wp
- IFD FUNZIP
- IFD CRYPT
- xref _encrypted
- xref _update_keys ; int update_keys(int)
- xref _decrypt_byte ; int decrypt_byte(void)
- ENDC ; CRYPT
- xref _in
- xref _getc ; int getc(FILE *)
- ELSE ; !FUNZIP
- xref _csize
- xref _incnt
- xref _mem_mode
- xref _inptr
- xref _readbyte ; int readbyte(void)
- ENDC
- xref _flush ; if FUNZIP: int flush(unsigned long)
- ; ...if !FUNZIP: int flush(unsigned char *, unsigned long *, int)
-
- ; Here are our register variables. Remember that int == short!
-
- b equr d2 ; unsigned long
- k equr d3 ; unsigned int <= 32
- e equr d4 ; unsigned int < 256 for most use
- w equr d5 ; unsigned int
- n equr d6 ; unsigned int
- d equr d7 ; unsigned int
-
- ; assert: we always maintain w and d as valid unsigned longs.
-
- t equr a2 ; struct huft *
- slide equr a3 ; unsigned char *
- mask equr a6 ; unsigned short *
-
- ; Couple other items we need:
-
- savregs reg d2-d7/a2/a3/a6
-
- WSIZE equ $8000 ; 32k... be careful not to treat as negative!
-
- IFD FUNZIP
- ; This does getc(in). Aztec version is based on #define getc(fp) in stdio.h
-
- IFD AZTEC
- xref __filbuf
- GETC MACRO
- move.l _in,a0
- move.l (a0),a1 ; in->_bp
- cmp.l 4(a0),a1 ; in->_bend
- blo.s gci\@
- move.l a0,-(sp)
- jsr __filbuf
- addq #4,sp
- bra.s gce\@
- gci\@: moveq #0,d0 ; must be valid as longword
- move.b (a1)+,d0
- move.l a1,(a0)
- gce\@:
- ENDM
- ELSE ; !AZTEC
- GETC MACRO
- move.l _in,-(sp)
- jsr _getc
- addq #4,sp
- ENDM
- ENDC ; AZTEC
- ENDC ; FUNZIP
-
- ; Input depends on the NEXTBYTE macro. This exists in three different forms.
- ; The first two are for fUnZip, with and without decryption. The last is for
- ; regular UnZip with or without decryption. The resulting byte is returned
- ; in d0 as a longword, and d1, a0, and a1 are clobbered.
-
- IFD FUNZIP
- IFD CRYPT
- NEXTBYTE MACRO
- GETC
- tst.w _encrypted
- beq.s nbe\@
- move.w d0,-(sp) ; save thru next call
- jsr _decrypt_byte
- eor.w d0,(sp) ; becomes arg to update_keys
- jsr _update_keys
- addq #2,sp
- nbe\@: ext.l d0 ; assert -1 <= d0 <= 255
- ENDM
- ELSE ; !CRYPT
- NEXTBYTE MACRO
- GETC ; nothing else in this case
- ENDM
- ENDC
- ELSE ; !FUNZIP
- NEXTBYTE MACRO
- subq.l #1,_csize
- bge.s nbg\@
- moveq #-1,d0 ; return EOF
- bra.s nbe\@
- nbg\@: subq.w #1,_incnt
- bge.s nbs\@
- jsr _readbyte
- bra.s nbe\@
- nbs\@: moveq #0,d0
- move.l _inptr,a0
- move.b (a0)+,d0
- move.l a0,_inptr
- nbe\@:
- ENDM
- ENDC
-
- ; FLUSH has different versions for fUnZip and UnZip. Arg must be a longword.
-
- IFD FUNZIP
- FLUSH MACRO
- move.l \1,-(sp)
- jsr _flush
- addq #4,sp
- ENDM
- ELSE ; !FUNZIP
- xref _mem_mode
- xref _outcnt
- FLUSH MACRO
- tst.w _mem_mode
- bne.s fm\@
- move.w #0,-(sp) ; unshrink flag: always false
- move.l \1,-(sp) ; length
- move.l slide,-(sp) ; buffer to flush
- jsr _flush
- lea 10(sp),sp
- bra.s fe\@
- fm\@: move.l w,_outcnt
- fe\@:
- ENDM
- ENDC ; FUNZIP
-
- ; Here are the two bit-grabbing macros, defined in their non-CHECK_EOF form:
- ;
- ; define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE)<<k;k+=8;}}
- ; define DUMPBITS(n) {b>>=(n);k-=(n);}
- ;
- ; NEEDBITS clobbers d0, d1, a0, and a1, none of which can be used as the arg
- ; to the macro specifying the number of bits. The arg can be a shortword memory
- ; address, or d2-d7. The result is copied into d1 as a word ready for masking.
- ; DUMPBITS has no side effects; the arg must be a d-register (or immediate in the
- ; range 1-8?) and only the lower byte is significant.
-
- NEEDBITS MACRO
- nb\@: cmp.w \1,k ; assert 0 < k <= 32 ... arg may be 0
- bhs.s ne\@
- NEXTBYTE ; returns in d0.l
- lsl.l k,d0
- or.l d0,b
- addq.w #8,k
- bra.s nb\@
- ne\@: move.w b,d1
- ENDM
-
- DUMPBITS MACRO
- lsr.l \1,b ; upper bits of \1 are ignored??
- sub.b \1,k
- ENDM
-
-
- ; ******************************************************************************
- ; Here we go, finally:
-
- xdef _flate_codes ; (pointer, pointer, int, int, pointer)
-
- _flate_codes:
- link a5,#-4
- movem.l savregs,-(sp)
- ; 8(a5) = tl, 12(a5) = td, 16(a5) = bl, 18(a5) = bd, 20(a5) = slide,
- ; -2(a5) = ml, -4(a5) = md. Here we cache some globals and args:
- move.l 20(a5),slide
- lea _mask,mask
- move.l _bb,b
- move.w _bk,k
- moveq #0,w ; keep this usable as longword
- move.w _wp,w
- moveq #0,e ; keep this usable as longword too
- move.w 16(a5),d0
- add.w d0,d0
- move.w (mask,d0.w),-2(a5) ; ml = mask[bl]
- move.w 18(a5),d0
- add.w d0,d0
- move.w (mask,d0.w),-4(a5) ; md = mask[bd]
-
- main_loop:
- NEEDBITS 16(a5) ; bl
- and.w -2(a5),d1 ; ml
- mulu #SIZEOF_HUFT,d1
- move.l 8(a5),a0 ; tl
- lea (a0,d1.l),t
- move.b h_e(t),e
- cmp.w #16,e
- bls.s topdmp
- intop: moveq #1,d0
- cmp.w #99,e
- beq return ; error in zipfile
- move.b h_b(t),d0
- DUMPBITS d0
- sub.w #16,e
- NEEDBITS e
- move.w e,d0
- add.w d0,d0
- and.w (mask,d0.w),d1
- mulu #SIZEOF_HUFT,d1
- move.l h_t(t),a0
- lea (a0,d1.l),t
- move.b h_e(t),e
- cmp.w #16,e
- bgt.s intop
- topdmp: move.b h_b(t),d0
- DUMPBITS d0
-
- cmp.w #16,e ; is this huffman code a literal?
- bne lenchk ; no
- move.w h_n(t),d0 ; yes
- move.b d0,(slide,w.l) ; stick in the decoded byte
- addq.w #1,w
- cmp.w #WSIZE,w
- blo main_loop
- FLUSH w
- moveq #0,w
- bra main_loop ; do some more
-
- lenchk: cmp.w #15,e ; is it an end-of-block code?
- beq finish ; if yes, we're done
- NEEDBITS e ; no: we have a duplicate string
- move.w e,d0
- add.w d0,d0
- and.w (mask,d0.w),d1
- move.w h_n(t),n
- add.w d1,n ; length of block to copy
- DUMPBITS e
- NEEDBITS 18(a5) ; bd
- and.w -4(a5),d1 ; md
- mulu #SIZEOF_HUFT,d1
- move.l 12(a5),a0 ; td
- lea (a0,d1.l),t
- move.b h_e(t),e
- cmp.w #16,e
- bls.s middmp
- inmid: moveq #1,d0
- cmp.w #99,e
- beq return ; error in zipfile
- move.b h_b(t),d0
- DUMPBITS d0
- sub.w #16,e
- NEEDBITS e
- move.w e,d0
- add.w d0,d0
- and.w (mask,d0.w),d1
- mulu #SIZEOF_HUFT,d1
- move.l h_t(t),a0
- lea (a0,d1.l),t
- move.b h_e(t),e
- cmp.w #16,e
- bgt.s inmid
- middmp: move.b h_b(t),d0
- DUMPBITS d0
- NEEDBITS e
- move.w e,d0
- add.w d0,d0
- and.w (mask,d0.w),d1
- move.l w,d
- sub.w h_n(t),d
- sub.w d1,d ; distance back to block to copy
- DUMPBITS e
-
- indup: move.w #WSIZE,e ; violate the e < 256 rule
- and.w #WSIZE-1,d
- cmp.w d,w
- blo.s ddgw
- sub.w w,e
- bra.s dadw
- ddgw: sub.w d,e
- dadw: cmp.w n,e
- bls.s delen
- move.w n,e
- delen: sub.w e,n ; size of sub-block to copy
- move.l slide,a0
- move.l a0,a1
- add.l w,a0 ; w and d are valid longwords
- add.l d,a1
- move.w e,d0
- subq #1,d0 ; assert >= 0 if sign extended
- dspin: move.b (a1)+,(a0)+ ; string is probably short, so
- dbra d0,dspin ; don't use any fancier copy method
- add.w e,w
- add.w e,d
- cmp.w #WSIZE,w
- blo.s dnfl
- FLUSH w
- moveq #0,w
- dnfl: tst.w n ; need to do more sub-blocks?
- bne indup ; yes
- moveq #0,e ; restore zeroness in upper bytes
- bra main_loop ; do some more
-
- finish: move.w w,_wp ; restore cached globals
- move.w k,_bk
- move.l b,_bb
- moveq #0,d0 ; return "no error"
- return: movem.l (sp)+,savregs
- unlk a5
- rts
-